package com.ezlcp.log.web;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.ezlcp.commons.base.db.BaseService;
import com.ezlcp.commons.base.entity.BaseEntity;
import com.ezlcp.commons.base.entity.JsonPageResult;
import com.ezlcp.commons.base.entity.JsonResult;
import com.ezlcp.commons.base.entity.QueryData;
import com.ezlcp.commons.base.search.QueryFilter;
import com.ezlcp.commons.base.search.QueryFilterBuilder;
import com.ezlcp.commons.tool.BeanUtil;
import com.ezlcp.commons.tool.StringUtils;
import com.ezlcp.commons.utils.ContextUtil;
import com.ezlcp.commons.utils.ExceptionUtil;
import com.ezlcp.commons.utils.FileUtil;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 包名：com.ezlcp.commons.web.controller
 * 功能描述：提供控制器一些基础方法，如获得i18n国际化的方法等
 */
@RestController
public  abstract class BaseController<E extends BaseEntity<? extends Serializable>>  {
    protected Logger logger=LoggerFactory.getLogger(BaseController.class);

    /**
     *
     * @return
     */
    public abstract BaseService<E> getBaseService();

    /**
     * 导出接口。
     * @return
     */
    protected   IExport getExport(){
        return null;
    }

    /**
     * 获取注释。
     * @return
     */
    public abstract String  getComment();



    /**
     * 子类可以添加对这个过滤器添加条件。
     * @param filter
     */
    protected void handleFilter(QueryFilter filter){
        String tenantId= ContextUtil.getCurrentTenantId();
        if(StringUtils.isNotEmpty(tenantId)){
            filter.addQueryParam("Q_tenant_id_S_EQ",tenantId);
        }
    }

    /**
     * 返回当前上下文的租户ID
     * @return
     */
    protected String getCurrentTenantId(){
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        var request = attributes.getRequest();
        String tenantId=request.getParameter("tenantId");
        if(StringUtils.isEmpty(tenantId)){
            tenantId= ContextUtil.getCurrentTenantId();
        }
        return tenantId;
    }

    /**
     * 子类可以增加这个过滤器处理数据
     * @param page
     */
    protected void handlePage(IPage page){

    }

    /**
     * 查询列表时，可以复写这个方法对列表进行更改。
     * @param list
     */
    protected void handleList(List list){

    }

    /**
     * 子类可以增加这个过滤器处理数据
     * @param ent
     */
    protected void handleData(E ent){

    }

    protected JsonResult beforeSave(E ent) {
        return  JsonResult.Success();
    }

    protected JsonResult beforeRemove(List<String> list){
        return  JsonResult.Success();
    }

    @Autowired
    protected HttpServletRequest request;

    @Operation(summary="根据主键ID删除记录", description="根据主键ID删除记录,parameters is {ids:'1,2'}")
    @PostMapping("del")
    public JsonResult del(@RequestParam(value = "ids") String ids){

        if(StringUtils.isEmpty(ids)){
            return new JsonResult(false,"common.paramError");
        }
        String[] aryId=ids.split(",");
        List list= Arrays.asList(aryId);

        JsonResult rtn= beforeRemove(list);
        if(!rtn.isSuccess()){
            return rtn;
        }
        JsonResult result=JsonResult.getSuccessResult("common.delSuccess");
        for (Object id: list) {
            String idStr=id.toString();
            E ent=getBaseService().get(idStr);
            if(ent==null){
                continue;
            }
        }

        getBaseService().delete(list);
        return result;
    }


    @Operation( summary="保存业务数据记录", description="根据提交的业务JSON数据保存业务数据记录")
    @Parameter(name = "entity",description = "实体对象")
    @PostMapping("/save")
    public JsonResult save(@Validated  @RequestBody E entity, BindingResult validResult) throws Exception{
        JsonResult result=handValid(validResult);
        if(!result.isSuccess()){
            return result;
        }

        Serializable pkId= entity.getPkId();
        String str="";
        String operation="";
        try{
            result= beforeSave(entity);
            if(!result.isSuccess()){
                return result;
            }
            if(BeanUtil.isEmpty(pkId)){
                getBaseService().insert(entity);

                str="common.addSuccess";
            }else{
                getBaseService().update(entity);
                str="user.updateSuccess";
            }
            result=JsonResult.getSuccessResult(str);
            result.setData(entity);
        } catch(Exception ex){
            String errMsg= ExceptionUtil.getExceptionMessage(ex);

            if(BeanUtil.isEmpty(pkId)){
                str="common.addFail";
            }else{
                str="user.updateFail";
            }
            result=JsonResult.getFailResult(str);
            result.setData(errMsg);
        }
        return result;
    }

    /**
     * 检查数据是否合法
     * @param validResult
     * @return
     */
    public JsonResult handValid(BindingResult validResult){
        if(!validResult.hasErrors()){
            return  JsonResult.Success();
        }
        JsonResult result=JsonResult.Fail("common.formValidationFail");
        List<ObjectError> allErrors = validResult.getAllErrors();
        StringBuilder sb=new StringBuilder();
        for(ObjectError error:allErrors){
            if(error instanceof FieldError){
                sb.append("["+((FieldError)error).getField()+"]");
            }
            sb.append( error.getDefaultMessage());
            sb.append("\r\n");
        }
        result.setData( sb.toString());

        return  result;

    }

    /**
     * 获得所有查询数据列表，不传入条件时，则返回所有的记录
     * @return
     * @throws Exception
     */
    @Operation( summary="★.多条件分页查询",
            description = "<b>查询参数params详细说明:</b>" +
                    "<br>每个参数名格式为：Q_数据库字段名_字段类型缩写_操作符缩写，参数值为查询条件值。" +
                    "<br>数据库字段名，如果是多表关联查询，且有字段名相同，就要加上“表名.”作为前缀，或者“表别名.”" +
                    "<br>字段类型缩写：S:字符串，L:长整型，I:整形，DB:DOUBLE，BD:BIGDECIMAL，F:FLOAT，SN:SHORT，D:日期类型，" +
                    "<br>操作符缩写：EQ:=，NEQ:!=，GT:>，GE:>=，LT:<，LE:<=，LK:全匹配，RIK:右匹配，LEK:左匹配，ISNULL:空，NOTNULL:非空" +
                    "<br>例如：{ \"Q_name_S_LK\": \"王\",  \"Q_user_type_S_EQ\": \"staff\"}，表示查询name字段中包含“王”字，且user_type字段值等于\"staff\"的记录;" +
                    "<br>前端查询输入框控件可绑定到类似“params.Q_name_S_LK”的变量，然后将params对象整体组装成JSON格式传到后台即可。")
    @PostMapping(value="/query")
    public JsonPageResult query(@RequestBody QueryData queryData) throws Exception{
        JsonPageResult jsonResult=JsonPageResult.getSuccess("common.returnDataSuccess");
        try{
            ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
            var request = servletRequestAttributes.getRequest();
            String url=request.getRequestURI();

            long start=System.currentTimeMillis();
            QueryFilter filter=QueryFilterBuilder.createQueryFilter(queryData);
            handleFilter(filter);
            IPage page= getBaseService().query(filter,queryData.getKey());
            handlePage(page);
            jsonResult.setPageData(page);
            logger.info("url:" +url +",escape time:" + (System.currentTimeMillis()-start) +"ms");
        }catch (Exception ex){
            jsonResult.setSuccess(false);
            logger.error(ExceptionUtil.getExceptionMessage(ex));
            jsonResult.setMessage(ExceptionUtil.getExceptionMessage(ex));
        }
        return jsonResult;
    }

    //@Operation( summary="根据条件查询业务数据记录", notes="根据条件查询业务数据记录")
   // @PostMapping(value="/queryList")
    public JsonResult queryList(@RequestBody QueryData queryData) throws Exception{
        JsonPageResult jsonResult=JsonPageResult.getSuccess("common.returnDataSuccess");
        try{
            ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
            var request = servletRequestAttributes.getRequest();
            String url=request.getRequestURI();

            long start=System.currentTimeMillis();
            QueryFilter filter=QueryFilterBuilder.createQueryFilter(queryData);
            handleFilter(filter);
            List list= getBaseService().queryList(filter);
            handleList(list);
            jsonResult.setData(list);

            logger.info("url:" +url +",escape time:" + (System.currentTimeMillis()-start) +"ms");

        }catch (Exception ex){
            jsonResult.setSuccess(false);
            logger.error(ExceptionUtil.getExceptionMessage(ex));
            jsonResult.setMessage(ExceptionUtil.getExceptionMessage(ex));
        }
        return jsonResult;
    }

    /**
     * 根据主键查询记录详细信息
     * @param pkId
     * @return
     */
    @Operation( summary="根据主键查询业务数据详细信息", description="根据主键查询业务数据详细信息")
    @PostMapping("/get")
    public JsonResult<E> get(@RequestParam (value="pkId") String pkId){
        JsonResult result=JsonResult.Success();
        result.setShow(false);
        if(ObjectUtils.isEmpty(pkId)){
            return result.setData(new Object());
        }
        E ent=getBaseService().get(pkId);
        handleData(ent);
        return result.setData(ent);
    }

    @Operation( summary="根据主键IDS查询业务数据详细信息", description="根据主键IDS查询业务数据详细信息")
    @PostMapping("/getByIds")
    public JsonResult<E> getByIds(@RequestParam (value="ids") String ids){
        JsonResult result=JsonResult.Success();
        result.setShow(false);
        if(ObjectUtils.isEmpty(ids)){
            return result.setData(new Object());
        }
        String[] aryId=ids.split(",");
        List<String> idList = Arrays.asList(aryId);
        List<E> byIds = getBaseService().getByIds(idList);
        return result.setData(byIds);
    }



    //@ApiOperation("查询结果导出")
    //@PostMapping("/listExport")
    public void listExport(@RequestBody QueryData param){
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        var response=attributes.getResponse();
        try {
            String[] all=null;
            if(param.getParams().containsKey("isQuery")){
                QueryFilter filter = QueryFilterBuilder.createQueryFilter(param);
                List<? extends BaseEntity> lists= getBaseService().queryList(filter);
                if(lists==null){
                    throw new Exception("导出失败，没有查询结果。");
                }
                List<String> ids=new ArrayList<>();
                for (BaseEntity list : lists) {
                    ids.add((String) list.getPkId());
                }
                all = ids.toArray(new String[ids.size()]);
            }
            else{
                String ids = param.getParams().get("ids");
                if(StringUtils.isEmpty(ids)){
                    throw new RuntimeException("导出失败，请选择要导出的记录。");
                }
                all = ids.split(",");
            }
            IExport export=getExport();

            StringBuilder sb=new StringBuilder();
            sb.append("导出 "+getComment()+ " :");


            Map<String,String> map=new HashMap<>();
            for(String id : all) {

                if(export==null){
                    logger.debug("请实现IExport接口!");
                    continue;
                }
                JSONObject json=getExport().doExportById(id,sb);
                String fileName =id+".json";
                String defStr = JSONObject.toJSONString(json);
                map.put(fileName,defStr);
            }


            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
            String downFileName = getComment() +"_" + sdf.format(new Date());
            FileUtil.downloadZip(response,downFileName,map);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }




}
